/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package iluscodelogica;

import excepciones.InterpreteException;

/**
 *
 * @author Ruben
 */
public class MaquinaVirtual extends Thread {

    Robot robot;
   
    //boolean ctrRobot;
    private boolean estado;
    private int contadorAlg;
    private Algoritmo algoritmo;
    private Thread padre;


    public MaquinaVirtual(Robot r, Algoritmo a) {
        robot = r;
        algoritmo = a;
    }
   

    public Robot getRobot() {
        return robot;
    }

    

   public void setPadre(Thread padre) throws InterruptedException{

        this.padre = padre;

    }
   
   


    @Override
    public void run() {

        try {
            if(padre != null) {

               padre.join(); // Encadenamos

            }

            ejecutar(algoritmo);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    private int getContadorAlgoritmo() {
        
        return contadorAlg;
    }

    private void setContadorAlgoritmo(int nuevoCA) {
        contadorAlg = nuevoCA;
    }

    private Object getElementosAlgoritmo(int ubica) {
        
        return algoritmo.getElemento(ubica);
    }

    private boolean ejecutar(Algoritmo a, int iniciarCA) {
       
        int tmpCP = contadorAlg;
        Algoritmo tmpProg = algoritmo;

        contadorAlg = iniciarCA;
        algoritmo = a;
        Instruccion i = algoritmo.getInstruccion(contadorAlg);

        while (!Instruccion.REGRESAR.equals(i)) {
            estado = i.ejecutar(this);
            contadorAlg += 1;
            i = algoritmo.getInstruccion(contadorAlg);
        }

        contadorAlg = tmpCP;
        algoritmo = tmpProg;

        return true;
    }

    public boolean rama() {
        
        Object o = getElementosAlgoritmo(getContadorAlgoritmo() + 1);
        int salto = ((Integer) o).intValue();

        setContadorAlgoritmo(salto - 1);
        return true;
    }

    public boolean subRama() {
        
        if (!estado) {
            Object o = getElementosAlgoritmo(getContadorAlgoritmo() + 1);
            int salto = ((Integer) o).intValue();

            setContadorAlgoritmo(salto - 1);
        } else {

            setContadorAlgoritmo(getContadorAlgoritmo() + 1);
        }
        return true;
    }

    public boolean repetir(){
        
        int limite;
        int salto;
        int cuerpoBucle;

        Object o = getElementosAlgoritmo(getContadorAlgoritmo() + 1);
        limite = ((Integer) o).intValue();

        o = getElementosAlgoritmo(getContadorAlgoritmo() + 2);
        salto = ((Integer) o).intValue();

        cuerpoBucle = getContadorAlgoritmo() + 3;


        for (int k = 0; k < limite; k++) {
            ejecutar(algoritmo, cuerpoBucle);
        }


        setContadorAlgoritmo(salto - 1);
        return true;

    }

    public boolean llamadaProc(){
        Object o = getElementosAlgoritmo(getContadorAlgoritmo() + 1);
        int subrutina = ((Integer) o).intValue();
        ejecutar(algoritmo, subrutina);

        setContadorAlgoritmo(getContadorAlgoritmo() + 1);
        return true;
    }

    public boolean ejecutar(Algoritmo a) throws InterpreteException {
        return ejecutar(a, a.getDirInicio());
    }
}
